#include "stdhlp.h"
#include "Win32.h"
#include "WinForm.h"


WinForm::WinForm(HINSTANCE hInst, wstring caption, wstring classname) :
	mhInst(hInst)
{
	// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
	
	sWndCaption		= caption;
	sAppClassName	= classname;
	iWndWidth		= 0;
	iWndHeight		= 0;
	mhWnd			= NULL;
}


WinForm::~WinForm(){}


HWND const& WinForm::WndHandle() const
{	
	return mhWnd; 
}


HINSTANCE const& WinForm::WndInstance() const
{
	return mhInst;
}


void WinForm::Init(UINT width, UINT height)
{
	bool FAILED = false;

	// Create Window Class Struct to hold description
	WNDCLASSEX wcex;
	// Clear struct with ZeroMemory
	ZeroMemory(&wcex, sizeof(WNDCLASSEX));

	wcex.cbSize			= sizeof(WNDCLASSEX); // size of struct
	wcex.style			= CS_HREDRAW | CS_VREDRAW; // Redraw Window
	wcex.lpfnWndProc	= MainWndProc; // Pointer to window procedure
	wcex.hInstance		= mhInst; // A handle to the instance that contains the window procedure for the class.
	wcex.hIcon			= LoadIcon(NULL, IDI_APPLICATION); // Icon to display
	wcex.hCursor		= LoadCursor(mhInst, IDC_ARROW); // A handle to the class cursor. 
	wcex.hbrBackground	= (HBRUSH)COLOR_WINDOW; // Color of Client Rectangle as HBRUSH
	wcex.lpszClassName  = sAppClassName.c_str(); // Name of the window's class

	//Define a class atom (Unique bit identifier for our class)
	ZeroMemory(&aWndUID, sizeof(ATOM));
	FAILED = ((aWndUID = RegisterClassEx(&wcex)) == NULL);

	if (FAILED)
	{
		MessageBox(NULL, L"Failed to Register Class!", L"RegisterClassEx failed!", NULL);
		PostQuitMessage(0);
	}

	// Define Window Style
	DWORD exWndStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
	DWORD wndStyle	 = WS_OVERLAPPED   | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

	// Calculate the correct size of the window so that the client rect area
	// is the desired width x height.
	POINT WndRect = CalcWndRect(iWndWidth  = width, 
								iWndHeight = height, 
								wndStyle);

	// Create Window
	mhWnd = CreateWindowEx(exWndStyle, // Extension of Window Style
						   sAppClassName.c_str(), // The name of the class our window will use
						   sWndCaption.c_str(), // The title of the window
						   wndStyle, // Window Style
						   0, // X-Position on the screen
						   0, // Y-Position on the screen
						   (UINT)WndRect.x, // Window Width
						   (UINT)WndRect.y, // Window height
						   NULL, // No parent window
						   NULL, // No menu bar
						   mhInst, // Instance handle
						   // Pass 'this' pointer to the 'CREATESTRUCT' structure pointer. We will retrieve 'this' 
						   // pointer through the main window procedure function. The 'lParam' param of the 'WM_CREATE'
						   // message will be a CREATESTRUCT pointer that points to 'this'. The 'WM_CREATE' message
						   // will be called before 'CreateWindowEx' returns but the main window procedure will know
						   // our window has been created and we can handle our message handling inside that scope.
						   this);

	// Evaluate if the window was created successfully
	FAILED = (mhWnd == NULL);

	if (FAILED)
	{
		MessageBox(NULL, L"Failed to Create Window!", L"CreateWindowEx failed!", NULL);
		PostQuitMessage(0);
	}

	// Display the window on the screen.
	ShowWindow(mhWnd, SW_SHOWNORMAL);
	UpdateWindow(mhWnd);
}


int WinForm::Run()
{
	// MSG struct contains message information from a thread's message queue.
	MSG msg = { 0 };
	// If the application hasn't requested to be closed check if there
	// is a message in the queue and store the result in 'msg'.
	while (msg.message != WM_QUIT)
	{
		// Do not filter PeekMessage by Window Handle. This will prevent
		// PeekMessage from getting WM_QUIT which is not a window associated
		// message and cause a deadlock. For other reasons as to why not to
		// overfilter:
		// http://blogs.msdn.com/b/oldnewthing/archive/2005/02/09/369804.aspx
		if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
		{
			// Translate keystroke messages into the right format
			TranslateMessage(&msg);
			// Send the message to the WindowProc function
			DispatchMessage(&msg);
		}
	}
	// return this part of the WM_QUIT message to Windows.
	return (int)msg.wParam;
}

LRESULT WinForm::MsgProc(UINT const& uMsg, WPARAM const& wParam, LPARAM const& lParam)
{
	switch (uMsg)
	{
		case WM_DESTROY:
			PostQuitMessage(0);
	}
	return DefWindowProc(mhWnd, uMsg, wParam, lParam);
}